// 4主机（0、1、2、3），6从机总线
// 其中主机3不得发生总线暂停

module rib(
    input  wire clk,
    input  wire rstn,

    // master 0 interface
    input  wire         m0_req_i,   // 主设备0的总线操作请求
    input  wire         m0_wen_i,   // 主设备0的写使能
    input  wire[31:0]   m0_addr_i,  // 主设备0想要读写的地址
    input  wire[31:0]   m0_wdata_i, // 主设备0想要写的数据
    output reg[31:0]    m0_rdata_o, // 主设备0想要读的数据

    // master 1 interface
    input  wire         m1_req_i,   // 主设备1的总线操作请求
    input  wire         m1_wen_i,   // 主设备1的写使能
    input  wire[31:0]   m1_addr_i,  // 主设备1想要读写的地址
    input  wire[31:0]   m1_wdata_i, // 主设备1想要写的数据
    output reg[31:0]    m1_rdata_o, // 主设备1想要读的数据

    // master 2 interface
    input  wire         m2_req_i,   // 主设备2的总线操作请求
    input  wire         m2_wen_i,   // 主设备2的写使能
    input  wire[31:0]   m2_addr_i,  // 主设备2想要读写的地址
    input  wire[31:0]   m2_wdata_i, // 主设备2想要写的数据
    output reg[31:0]    m2_rdata_o, // 主设备2想要读的数据

    // master 3 interface
    input  wire         m3_req_i,   // 主设备3的总线操作请求
    input  wire         m3_wen_i,   // 主设备3的写使能
    input  wire[31:0]   m3_addr_i,  // 主设备3想要读写的地址
    input  wire[31:0]   m3_wdata_i, // 主设备3想要写的数据
    output reg[31:0]    m3_rdata_o, // 主设备3想要读的数据

    // slave 0 interface
    output reg          s0_wen_o,   // 从设备0的写使能
    output reg[31:0]    s0_addr_o,  // 从设备0需要操作的地址
    output reg[31:0]    s0_wdata_o, // 从设备0写入的数据
    input  wire[31:0]   s0_rdata_i, // 从设备0读出的数据

    // slave 1 interface
    output reg          s1_wen_o,   // 从设备1的写使能
    output reg[31:0]    s1_addr_o,  // 从设备1需要操作的地址
    output reg[31:0]    s1_wdata_o, // 从设备1写入的数据
    input  wire[31:0]   s1_rdata_i, // 从设备1读出的数据

    // slave 2 interface
    output reg          s2_wen_o,   // 从设备2的写使能
    output reg[31:0]    s2_addr_o,  // 从设备2需要操作的地址
    output reg[31:0]    s2_wdata_o, // 从设备2写入的数据
    input  wire[31:0]   s2_rdata_i, // 从设备2读出的数据

    // slave 3 interface
    output reg          s3_wen_o,   // 从设备3的写使能
    output reg[31:0]    s3_addr_o,  // 从设备3需要操作的地址
    output reg[31:0]    s3_wdata_o, // 从设备3写入的数据
    input  wire[31:0]   s3_rdata_i, // 从设备3读出的数据

    // slave 4 interface
    output reg          s4_wen_o,   // 从设备4的写使能
    output reg[31:0]    s4_addr_o,  // 从设备4需要操作的地址
    output reg[31:0]    s4_wdata_o, // 从设备4写入的数据
    input  wire[31:0]   s4_rdata_i, // 从设备4读出的数据

    // slave 5 interface
    output reg          s5_wen_o,   // 从设备5的写使能
    output reg[31:0]    s5_addr_o,  // 从设备5需要操作的地址
    output reg[31:0]    s5_wdata_o, // 从设备5写入的数据
    input  wire[31:0]   s5_rdata_i, // 从设备5读出的数据

    output reg          hold_flag_o // 暂停流水线标志
);

// 固定四个主设备，同时采用优先级仲裁，因此设定四个仲裁等级
parameter[1:0] grant0 = 2'b00;
parameter[1:0] grant1 = 2'b01;
parameter[1:0] grant2 = 2'b10;
parameter[1:0] grant3 = 2'b11;

// 主设备输入的地址信号的前三位作为从设备的地址，因此该总线最多支持挂载8个从设备
parameter[2:0] slave0_addr = 3'b000;
parameter[2:0] slave1_addr = 3'b001;
parameter[2:0] slave2_addr = 3'b010;
parameter[2:0] slave3_addr = 3'b011;
parameter[2:0] slave4_addr = 3'b100;
parameter[2:0] slave5_addr = 3'b101;
parameter[2:0] slave6_addr = 3'b110;
parameter[2:0] slave7_addr = 3'b111;

reg[1:0]    grant;

// 仲裁逻辑
// 优先级从高到低：主设备0、主设备1、主设备2、主设备3
always @(*) begin
    if(m0_req_i == 1'b1) begin
        grant = grant0;
        hold_flag_o = 1'b1;
    end else if(m1_req_i == 1'b1) begin
        grant = grant1;
        hold_flag_o = 1'b1;
    end else if(m2_req_i == 1'b1) begin
        grant = grant2;
        hold_flag_o = 1'b1;
    end else begin
        grant = grant3;
        hold_flag_o = 1'b0;
    end
end

always @(*) begin
    m0_rdata_o = 'd0;
    m1_rdata_o = 'd0;
    m2_rdata_o = 'd0;
    m3_rdata_o = 'd0;

    s0_wen_o    = 1'b0;
    s0_addr_o   = 'd0;
    s0_wdata_o  = 'd0;
    s1_wen_o    = 1'b0;
    s1_addr_o   = 'd0;
    s1_wdata_o  = 'd0;
    s2_wen_o    = 1'b0;
    s2_addr_o   = 'd0;
    s2_wdata_o  = 'd0;
    s3_wen_o    = 1'b0;
    s3_addr_o   = 'd0;
    s3_wdata_o  = 'd0;
    s4_wen_o    = 1'b0;
    s4_addr_o   = 'd0;
    s4_wdata_o  = 'd0;
    s5_wen_o    = 1'b0;
    s5_addr_o   = 'd0;
    s5_wdata_o  = 'd0;

    case(grant)
        grant0 : begin
            case(m0_addr_i[31:29])
                slave0_addr : begin
                    s0_wen_o    = m0_wen_i;
                    s0_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s0_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s0_rdata_i;
                end
                slave1_addr : begin
                    s1_wen_o    = m0_wen_i;
                    s1_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s1_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s1_rdata_i;
                end
                slave2_addr : begin
                    s2_wen_o    = m0_wen_i;
                    s2_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s2_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s2_rdata_i;
                end
                slave3_addr : begin
                    s3_wen_o    = m0_wen_i;
                    s3_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s3_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s3_rdata_i;
                end
                slave4_addr : begin
                    s4_wen_o    = m0_wen_i;
                    s4_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s4_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s4_rdata_i;
                end
                slave5_addr : begin
                    s5_wen_o    = m0_wen_i;
                    s5_addr_o   = {3'b000, m0_addr_i[28:0]};
                    s5_wdata_o  = m0_wdata_i;
                    m0_rdata_o  = s5_rdata_i;
                end
                // slave6_addr : begin
                // end
                // slave7_addr : begin
                // end
                default : begin
                end
            endcase
        end
        grant1 : begin
            case(m1_addr_i[31:29])
                slave0_addr : begin
                    s0_wen_o    = m1_wen_i;
                    s0_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s0_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s0_rdata_i;
                end
                slave1_addr : begin
                    s1_wen_o    = m1_wen_i;
                    s1_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s1_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s1_rdata_i;
                end
                slave2_addr : begin
                    s2_wen_o    = m1_wen_i;
                    s2_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s2_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s2_rdata_i;
                end
                slave3_addr : begin
                    s3_wen_o    = m1_wen_i;
                    s3_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s3_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s3_rdata_i;
                end
                slave4_addr : begin
                    s4_wen_o    = m1_wen_i;
                    s4_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s4_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s4_rdata_i;
                end
                slave5_addr : begin
                    s5_wen_o    = m1_wen_i;
                    s5_addr_o   = {3'b000, m1_addr_i[28:0]};
                    s5_wdata_o  = m1_wdata_i;
                    m1_rdata_o  = s5_rdata_i;
                end
                // slave6_addr : begin
                // end
                // slave7_addr : begin
                // end
                default : begin
                end
            endcase
        end
        grant2 : begin
            case(m2_addr_i[31:29])
                slave0_addr : begin
                    s0_wen_o    = m2_wen_i;
                    s0_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s0_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s0_rdata_i;
                end
                slave1_addr : begin
                    s1_wen_o    = m2_wen_i;
                    s1_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s1_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s1_rdata_i;
                end
                slave2_addr : begin
                    s2_wen_o    = m2_wen_i;
                    s2_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s2_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s2_rdata_i;
                end
                slave3_addr : begin
                    s3_wen_o    = m2_wen_i;
                    s3_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s3_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s3_rdata_i;
                end
                slave4_addr : begin
                    s4_wen_o    = m2_wen_i;
                    s4_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s4_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s4_rdata_i;
                end
                slave5_addr : begin
                    s5_wen_o    = m2_wen_i;
                    s5_addr_o   = {3'b000, m2_addr_i[28:0]};
                    s5_wdata_o  = m2_wdata_i;
                    m2_rdata_o  = s5_rdata_i;
                end
                // slave6_addr : begin
                // end
                // slave7_addr : begin
                // end
                default : begin
                end
            endcase
        end
        grant3 : begin
            case(m3_addr_i[31:29])
                slave0_addr : begin
                    s0_wen_o    = m3_wen_i;
                    s0_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s0_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s0_rdata_i;
                end
                slave1_addr : begin
                    s1_wen_o    = m3_wen_i;
                    s1_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s1_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s1_rdata_i;
                end
                slave2_addr : begin
                    s2_wen_o    = m3_wen_i;
                    s2_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s2_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s2_rdata_i;
                end
                slave3_addr : begin
                    s3_wen_o    = m3_wen_i;
                    s3_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s3_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s3_rdata_i;
                end
                slave4_addr : begin
                    s4_wen_o    = m3_wen_i;
                    s4_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s4_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s4_rdata_i;
                end
                slave5_addr : begin
                    s5_wen_o    = m3_wen_i;
                    s5_addr_o   = {3'b000, m3_addr_i[28:0]};
                    s5_wdata_o  = m3_wdata_i;
                    m3_rdata_o  = s5_rdata_i;
                end
                // slave6_addr : begin
                // end
                // slave7_addr : begin
                // end
                default : begin
                end
            endcase
        end
        default : begin

        end
    endcase
end

endmodule